package nxu.it.movieapi.service.mongo;

import nxu.it.api.common.result.BasePage;
import nxu.it.api.common.result.Pageable;
import nxu.it.api.model.SimpleStaff;
import nxu.it.api.model.Staff;
import nxu.it.api.service.StaffService;
import nxu.it.api.service.param.StaffPageQueryParam;
import nxu.it.movieapi.Doc.StaffDoc;
import nxu.it.movieapi.service.mapper.StaffMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Optional;

@Component
public class StaffServiceMongoImpl implements StaffService {

    @Autowired
    private MongoTemplate template;

    @Autowired
    private StaffMapper staffMapper;

    @Override
    public Optional<Staff> findById(@NotNull Integer staffId) {
        Query query = new Query(Criteria.where("_id").is(staffId));
        StaffDoc staffDoc = template.findOne(query, StaffDoc.class);
        return Optional.ofNullable(staffMapper.fromDoc(staffDoc));
    }

    @Override
    public Pageable<SimpleStaff> page(@NotNull StaffPageQueryParam staffPageQueryParam) {
        String chineseName = staffPageQueryParam.getChineseName();
        String englishName = staffPageQueryParam.getEnglishName();
        String gender = staffPageQueryParam.getGender();
        String region = staffPageQueryParam.getRegion();

        Criteria criteria = new Criteria();
        if (chineseName != null && !chineseName.isBlank()) {
            criteria.and("chineseName").regex(chineseName, "i");
        }
        if (englishName != null && !englishName.isBlank()) {
            criteria.and("englishName").regex(englishName, "i");
        }
        if (gender != null && !gender.isBlank()) {
            criteria.and("gender").regex(gender, "i");
        }
        if (region != null && !region.isBlank()) {
            criteria.and("region").regex(region, "i");
        }

        Query query = new Query(criteria);

        // Sorting
        String orderDirection = staffPageQueryParam.getOrderDirection();
        String orderField = staffPageQueryParam.getOrderField();
        Sort sort = orderDirection.equalsIgnoreCase("asc") ? Sort.by(Sort.Direction.ASC, orderField) : Sort.by(Sort.Direction.DESC, orderField);
        query.with(sort);

        // Pagination
        int pageNumber = staffPageQueryParam.getPageNumber();
        int pageSize = staffPageQueryParam.getPageSize();
        query.with(PageRequest.of(pageNumber - 1, pageSize));

        long totalRow = template.count(query, StaffDoc.class);
        List<StaffDoc> staffDocList = template.find(query, StaffDoc.class);

        List<SimpleStaff> simpleStaffList = staffMapper.toSimpleStaffList(staffDocList);
        int totalPage = (int) Math.ceil((double) totalRow /  (double) pageSize);

        return new BasePage<>(simpleStaffList, pageNumber, pageSize, totalPage, (int) totalRow);
    }
}
